home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / fstab / fixperm.c < prev    next >
C/C++ Source or Header  |  1996-05-18  |  13KB  |  558 lines

  1. #include <limits.h>
  2. #include <ctype.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <pwd.h>
  7. #include <grp.h>
  8. #include <sys/stat.h>
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include "fstab.h"
  12. #include "../userconf/userconf.h"
  13. #include "../misc/misc.h"
  14. #include "../netconf/netconf.h"
  15. #include "../paths.h"
  16. #include "fstab.m"
  17.  
  18. /* #Specification: fixperm / strategy
  19.     The directory /usr/lib/linuxconf/conf.permissions contains
  20.     files describing the permissions of different packages.
  21.     The format of the file is rather simple.
  22.  
  23.     #
  24.     filespec owner group type permissions options ...
  25.     #
  26.  
  27.     The permissions are expressed in octal.
  28.  
  29.     type is one of those:
  30.  
  31.     #
  32.     b,major,minor:    block device
  33.     c,major,minor:    character device
  34.     f:    file
  35.     d:    directory
  36.     #
  37.  
  38.     Here are the options supported
  39.  
  40.     #
  41.     boot:        The check is done only at boot time. This is
  42.             especially intended for pseudo tty which need
  43.             special permissions. Those pty generally change
  44.             while the system is running. Normally, everything
  45.             is back to normal when the system goes down, except
  46.             when it crash. Unless the permissions are set
  47.             correctly, everything goes wrong: Debuggers, some
  48.             editors etc...
  49.     recurse:    filespec must be a directory. The
  50.             owner, group and permissions will be
  51.             applied to all file in that directory
  52.             and sudirectory.
  53.     required:    The file has to be there. An error
  54.             will be signaled if not. If the file
  55.             is a directory, it will be created.
  56.     #
  57. */
  58. #
  59. const int maxopt=3;
  60. struct SPEC_ONE{
  61.     const char *fpath;    // Path of the specification file
  62.     int noline;        // Current line in fpath
  63.     char path[PATH_MAX];
  64.     char owner[PATH_MAX];
  65.     char group[PATH_MAX];
  66.     char type[PATH_MAX];
  67.     int perm;
  68.     char opts[maxopt][PATH_MAX];
  69. };
  70.  
  71. /*
  72.     Print an error message with reference to the specification file
  73. */
  74. static void fixperm_error (SPEC_ONE &sp, const char *msg, ...)
  75. {
  76.     va_list list;
  77.     va_start (list,msg);
  78.     char buf[1000];
  79.     vsprintf (buf,msg,list);
  80.     va_end (list);
  81.     xconf_error (MSG_U(E_CONFFILE,"%s\n\n"
  82.         "In file %s, line %d\n"),buf,sp.fpath,sp.noline);
  83. }
  84.  
  85.  
  86.  
  87. struct FIXPERM_OPTIONS{
  88.     bool boot;
  89.     bool recurse;
  90.     bool required;
  91. };
  92.  
  93. enum FPERM_TYPE { FPERM_FILE, FPERM_DIR};
  94.  
  95. class FIXPERM_SPEC: public ARRAY_OBJ{
  96.     friend class FIXPERM_SPECS;
  97.     SSTRING path;
  98.     SSTRING owner;
  99.     SSTRING group;
  100.     FPERM_TYPE type;
  101.     int perm;
  102.     int dev;
  103.     FIXPERM_OPTIONS opts;
  104.     int uid;
  105.     int gid;
  106.     bool valid;        // Is this record valid
  107.     /*~PROTOBEG~ FIXPERM_SPEC */
  108. public:
  109.     FIXPERM_SPEC (SPEC_ONE&sp);
  110.     int check (void);
  111.     int create (void);
  112. private:
  113.     void parsedev (SPEC_ONE&sp);
  114. public:
  115.     /*~PROTOEND~ FIXPERM_SPEC */
  116. };
  117. /*
  118.     Parse the option of one spec
  119. */
  120. static int fixperm_parseopts (SPEC_ONE &sp, FIXPERM_OPTIONS &opts)
  121. {
  122.     int ret = 0;
  123.     opts.boot = opts.recurse = opts.required = false;
  124.     for (int i=0; i<maxopt; i++){
  125.         if (sp.opts[i][0] == '\0'){
  126.             break;
  127.         }else if (strcmp(sp.opts[i],"recurse")==0){
  128.             opts.recurse = true;
  129.         }else if (strcmp(sp.opts[i],"required")==0){
  130.             opts.required = true;
  131.         }else if (strcmp(sp.opts[i],"boot")==0){
  132.             opts.boot = true;
  133.         }else{
  134.             ret = -1;
  135.             fixperm_error (sp,MSG_U(E_IVLDOPT,"Invalid option %s")
  136.                 ,sp.opts[i]);
  137.         }
  138.     }
  139.     return ret;
  140. }
  141. /*
  142.     Parse a special device spec (b|c,major,minor)
  143.     Return -1 if any error or the encoded device number.
  144. */
  145. PRIVATE void FIXPERM_SPEC::parsedev (SPEC_ONE &sp)
  146. {
  147.     dev = -1;
  148.     const char *type = sp.type + 2;
  149.     if (isdigit(type[0])){
  150.         int major = atoi (type);
  151.         type = str_skipdig(type);
  152.         if (type[0] == ',' && isdigit(type[1])){
  153.             int minor = atoi(type+1);
  154.             dev = major*256 + minor;
  155.         }
  156.     }
  157.     if (dev == -1){
  158.         fixperm_error (sp,MSG_U(E_IVLDDEV
  159.             ,"Invalid device specification\n"
  160.             "Expect b|c,major,minor, got %s\n"),sp.type);
  161.     }
  162. }
  163.  
  164.  
  165. PUBLIC FIXPERM_SPEC::FIXPERM_SPEC(SPEC_ONE &sp)
  166. {
  167.     path.setfrom(sp.path);
  168.     owner.setfrom (sp.owner);
  169.     group.setfrom (sp.group);
  170.     perm = sp.perm;
  171.     dev = 0;
  172.     valid = true;
  173.     if (strcmp(sp.type,"d")==0){
  174.         perm |= S_IFDIR;
  175.     }else if (strcmp(sp.type,"f")==0){
  176.         perm |= S_IFREG;
  177.     }else if (strncmp(sp.type,"c,",2)==0){
  178.         perm |= S_IFCHR;
  179.         parsedev (sp);
  180.     }else if (strncmp(sp.type,"b,",2)==0){
  181.         perm |= S_IFBLK;
  182.         parsedev (sp);
  183.     }else{
  184.         fixperm_error (sp,MSG_U(E_IVLDTYPE
  185.             ,"Invalid type field \"%s\" (b, c, d or f expected)\n")
  186.             ,sp.type);
  187.         valid = false;
  188.     }
  189.     if (fixperm_parseopts(sp,opts)==-1){
  190.         valid = false;
  191.     }
  192.     struct passwd *p = getpwnam (sp.owner);
  193.     struct group  *g = getgrnam (sp.group);
  194.     uid = gid = 0;
  195.     if (p == NULL){
  196.         fixperm_error (sp,MSG_U(E_NOUSER
  197.             ,"No user \"%s\" defined on this system")
  198.             ,sp.owner);
  199.         valid = false;
  200.     }else{
  201.         uid = p->pw_uid;
  202.     }
  203.     if (g == NULL){
  204.         fixperm_error (sp,MSG_U(E_NOGROUP
  205.             ,"No group \"%s\" defined on this system")
  206.             ,sp.group);
  207.         valid = false;
  208.     }else{
  209.         gid = g->gr_gid;
  210.     }
  211. }
  212.  
  213. #if 0
  214. PUBLIC void FIXPERM_SPEC::print (FILE *fout)
  215. {
  216.     fprintf (fout,"%s %s %s %o"
  217.         ,path.get(),owner.get(),group.get(),perm);
  218.     if (opts.recurse) fputs (" recurse",fout);
  219.     if (opts.required) fputs (" required",fout);
  220.     fputc ('\n',fout);
  221. }
  222.  
  223. #endif
  224.  
  225. /*
  226.     Create an empty file or directory
  227.     Return -1 if any error.
  228. */
  229. PUBLIC int FIXPERM_SPEC::create()
  230. {
  231.     int ret = 0;
  232.     const char *fpath = path.get();
  233.     if (S_ISDIR(perm)){
  234.         ret = mkdir (fpath,0666);
  235.     }else if (S_ISCHR(perm) || S_ISBLK(perm)){
  236.         ret = mknod (fpath,perm,dev);
  237.     }else{
  238.         int fd = creat (fpath,O_WRONLY);
  239.         if (fd != -1){
  240.             close(fd);
  241.         }else{
  242.             ret = -1;
  243.         }
  244.     }
  245.     if (ret != 0
  246.         || chown (fpath,uid,gid) == -1
  247.         || chmod (fpath,perm) == -1){
  248.         ret = -1;
  249.     }
  250.     return ret;
  251. }
  252.  
  253. /*
  254.     Fix one file specification
  255. */
  256. PUBLIC int FIXPERM_SPEC::check()
  257. {
  258.     if (valid){
  259.         bool dook = !simul_ison();
  260.         struct stat st;
  261.         const char *fpath = path.get();
  262.         if (stat(fpath,&st)==-1){
  263.             /* #Specification: fixperm / symbolic links
  264.                 Symbolic links are often used to move things
  265.                 around in different file systems. The symbolic
  266.                 links are faking the original hierarchy. This complicates
  267.                 life for the "fixperm" functionnality of linuxconf.
  268.                 In fact, in different time, linuxconf can't produce
  269.                 a reliable status.
  270.  
  271.                 For example my mail spool directory is on an NFS server.
  272.                 Instead of mounting the server spool in /var/spool/mail,
  273.                 I use the amd automounter and set a symbolic links like
  274.                 this.
  275.  
  276.                 ln -s /n/server/var/spool/mail /var/spool/mail
  277.  
  278.                 Unfortunatly, linuxconf can't test the validity
  279.                 of /var/spool/mail until the network is up. This
  280.                 checking is annoying. It complains that /var/spool/mail
  281.                 is not a directory and so on.
  282.  
  283.                 So here is the patch. If a "something" has been
  284.                 replaced by a symbolic links and the destination
  285.                 of the link appears to be missing, linuxconf
  286.                 won't complain at all.
  287.             */
  288.             if (opts.required && lstat(fpath,&st)==-1){
  289.                 net_prtlog (MSG_U(L_CREATING
  290.                     ,"Creating %s %s\n")
  291.                     ,S_ISDIR(perm)
  292.                         ? MSG_U(L_DIRECTORY,"directory")
  293.                         : MSG_U(L_FILE,"file")
  294.                     ,fpath);
  295.                 if (dook) create();
  296.             }
  297.         }else if ((st.st_mode & S_IFMT)
  298.             != (perm & S_IFMT)){
  299.             net_prtlog (
  300.                 MSG_U(E_CANTCHG
  301.                     ,"**** Can't change the type of file %s\n"
  302.                      "     manual action required!\n")
  303.                 ,fpath);
  304.         }else if ((S_ISBLK(perm) || S_ISCHR(perm))
  305.             && st.st_rdev != dev){
  306.             net_prtlog (MSG_U(E_WRONGDEV,"Device file %s wrongly created\n"
  307.                     "\tExpected major %d, minor %d\n"
  308.                     "\tFound    major %d, minor %d\n"
  309.                     "\tManual action required\n")
  310.                     ,fpath,dev>>8,dev&0xff,st.st_rdev>>8,st.st_rdev&0xff);
  311.         }else{
  312.             if (st.st_uid != uid
  313.                 || st.st_gid != gid){
  314.                 if (dook) chown (fpath,uid,gid);
  315.                 net_prtlog (MSG_U(L_CHGOWN,"Changing owner of file %s "
  316.                     "to %s.%s\n")
  317.                     ,fpath,owner.get(),group.get());
  318.                 stat(fpath,&st);
  319.             }
  320.             if (st.st_mode != perm){
  321.                 if (dook) chmod (fpath,perm);
  322.                 net_prtlog (MSG_U(L_CHGPERM
  323.                     ,"Changing permissions  of file %s "
  324.                      "from %o to %o\n")
  325.                     ,fpath,st.st_mode,perm);
  326.             }
  327.         }
  328.     }
  329.     return 0;
  330. }
  331.  
  332. class FIXPERM_SPECS: public ARRAY{
  333.     /*~PROTOBEG~ FIXPERM_SPECS */
  334. public:
  335.     FIXPERM_SPECS (const char *fname);
  336.     int check (bool boottime);
  337.     int check (void);
  338.     FIXPERM_SPEC *getitem (int no);
  339.     /*~PROTOEND~ FIXPERM_SPECS */
  340. };
  341.  
  342. /*
  343.     Check and optionnally ajust permissions on some files
  344. */
  345. PUBLIC  FIXPERM_SPECS::FIXPERM_SPECS(const char *fname)
  346. {
  347.     SPEC_ONE sp;
  348.     sp.fpath = fname;
  349.     sp.noline = 1;
  350.     FILE *fin = xconf_fopen (sp.fpath,"r");
  351.     char buf[500];
  352.     /* #Specification: fixperm / file format / comments
  353.         The fixperm's spec file may contain blank lines and
  354.         line beginning with a # are comments.
  355.     */
  356.     while (fgets (buf,sizeof(buf)-1,fin)!=NULL){
  357.         strip_end (buf);
  358.         char *ptbuf = str_skip(buf);
  359.         if (ptbuf[0] != '\0' && ptbuf[0] != '#'){
  360.             sp.opts[0][0] = sp.opts[1][0] = sp.opts[2][0] = '\0';
  361.             if (sscanf(buf,"%s %s %s %s %o %s %s %s\n"
  362.                 ,sp.path,sp.owner,sp.group,sp.type,&sp.perm
  363.                 ,sp.opts[0],sp.opts[1],sp.opts[2]) < 5){
  364.                 fixperm_error (sp,MSG_U(E_IVLDLINE,"Invalid line"));
  365.             }else{
  366.                 add (new FIXPERM_SPEC (sp));
  367.             }
  368.             sp.noline++;
  369.         }
  370.     }
  371. }
  372.  
  373.  
  374. PUBLIC FIXPERM_SPEC *FIXPERM_SPECS::getitem(int no)
  375. {
  376.     return (FIXPERM_SPEC*)ARRAY::getitem(no);
  377. }
  378.  
  379. PUBLIC int FIXPERM_SPECS::check(bool boottime)
  380. {
  381.     int ret = 0;
  382.     for (int i=0; i<getnb(); i++){
  383.         FIXPERM_SPEC *chk = getitem(i);
  384.         /* #Specification: fixperm / boot time check
  385.             Some checking is done only at boot time
  386.             because permission and ownership change while
  387.             working. This is especially true for pty's.
  388.         */
  389.         if (chk->opts.boot){
  390.             if (boottime){
  391.                 if (chk->check() == -1) ret = -1;
  392.             }
  393.         }else{
  394.             if (chk->check() == -1) ret = -1;
  395.         }
  396.     }
  397.     return ret;
  398. }
  399.  
  400. PUBLIC int FIXPERM_SPECS::check()
  401. {
  402.     return check (false);
  403. }
  404.  
  405.  
  406. static int fixperm_check (
  407.     const char *prefix,
  408.     SSTRINGS &lst,
  409.     bool boottime)
  410. {
  411.     int ret = 0;
  412.     for (int i=0; i<lst.getnb(); i++){
  413.         const char *ptf = lst.getitem(i)->get();
  414.         if (ptf[0] != '\0'){
  415.             char path[PATH_MAX];
  416.             sprintf (path,"%s/%s",prefix,ptf);
  417.             FIXPERM_SPECS specs(path);
  418.             if (specs.check(boottime) == -1) ret = -1;
  419.         }
  420.     }
  421.     return ret;
  422. }
  423.  
  424.  
  425. /*
  426.     Check and optionnally ajust permissions on some files
  427.  
  428.     Return -1 if any error.
  429. */
  430. static int fixperm_check(bool boottime)
  431. {
  432.     /* #Specification: fixperm / /var/lib/conf.permissions / strategy
  433.         Linuxconf provide its own set of permissions files
  434.         int /usr/lib/linuxconf/conf.permissions. These are
  435.         supplied with linuxconf and will probably get updated
  436.         at each new releases.
  437.  
  438.         You can create permission files in /var/lib/conf.permissions.
  439.         If you create a permission file with the same name as
  440.         one in /usr/lib/linuxconf/conf.permissions, yours will
  441.         take precedence. This allows you to do customisation
  442.         of those file without fearing the next update :-)
  443.     */
  444.     SSTRINGS usr_tb;
  445.     dir_getlist(USR_LIB_CONF_PERMISSIONS,usr_tb);
  446.     SSTRINGS var_tb;
  447.     dir_getlist(VAR_LIB_CONF_PERMISSIONS,var_tb);
  448.     for (int v=0; v<var_tb.getnb(); v++){
  449.         int u = usr_tb.lookup(var_tb.getitem(v));
  450.         if (u != -1) usr_tb.getitem(u)->setfrom("");
  451.     }
  452.     return fixperm_check (USR_LIB_CONF_PERMISSIONS,usr_tb,boottime)
  453.         | fixperm_check (VAR_LIB_CONF_PERMISSIONS,var_tb,boottime);
  454. }
  455. /*
  456.     Check and optionnally ajust permissions on some files
  457.  
  458.     Return -1 if any error.
  459. */
  460. int fixperm_check()
  461. {
  462.     return fixperm_check(false);
  463. }
  464. /*
  465.     Check and optionnally ajust permissions on some files at boot time
  466.  
  467.     Return -1 if any error.
  468. */
  469. int fixperm_check_boot()
  470. {
  471.     simul_init();
  472.     int ret = fixperm_check(true);
  473.     if (ret != -1 && simul_prompt()==1){
  474.         ret = fixperm_check(true);
  475.     }
  476.     return ret;
  477. }
  478.  
  479. /*
  480.     Check and optionnally ajust permissions on some system
  481. */
  482. static int fixperm_check(int nb, char *tb[])
  483. {
  484.     int ret;
  485.     /* #Specification: fixperm / command line / args
  486.         "fixperm --update" or "fixperm --status" without
  487.         further arguments will check all system in
  488.         /usr/lib/linuxconf/conf.permissions/
  489.         and /var/lib/conf.permissions/.
  490.  
  491.         If some argument are provided, they are taken
  492.         as specific system to check in either
  493.         /usr/lib/linuxconf/conf.permissions/ or
  494.         /var/lib/conf.permissions/.
  495.  
  496.         If one argument start with a /, it is taken as an absolute
  497.         path to a specification file using the same format
  498.         as the ones in /usr/lib/linuxconf/conf.permissions/.
  499.     */
  500.     if (nb == 0){
  501.         ret = fixperm_check();    // Check all
  502.     }else{
  503.         ret = 0;
  504.         SSTRINGS usr_tb;
  505.         dir_getlist(USR_LIB_CONF_PERMISSIONS,usr_tb);
  506.         SSTRINGS var_tb;
  507.         dir_getlist(VAR_LIB_CONF_PERMISSIONS,var_tb);
  508.         for (int i=0; i<nb; i++){
  509.             char *arg = tb[i];
  510.             char path[PATH_MAX];
  511.             if (arg[0] == '/'){
  512.                 strcpy (path,arg);
  513.             }else if (var_tb.lookup(arg) !=-1){
  514.                 sprintf (path,"%s/%s",VAR_LIB_CONF_PERMISSIONS
  515.                     ,arg);
  516.             }else if (usr_tb.lookup(arg) !=-1){
  517.                 sprintf (path,"%s/%s",USR_LIB_CONF_PERMISSIONS
  518.                     ,arg);
  519.             }
  520.             FIXPERM_SPECS specs(path);
  521.             if (specs.check() == -1) ret = -1;
  522.         }
  523.     }
  524.     return ret;
  525. }
  526.  
  527. static void usage()
  528. {
  529.     fprintf (stderr,
  530.         "fixperm --status\n"
  531.         "fixperm --update [ system ... ]\n"
  532.         );
  533. }
  534.  
  535. int fstab_fixperm (int argc, char *argv[])
  536. {
  537.     int ret = -1;
  538.     if (argc == 1){
  539.         usage();
  540.     }else{
  541.         if (strcmp(argv[1],"--status")==0){
  542.             simul_init(stdout);
  543.             ret = fixperm_check (argc-2,argv+2);
  544.         }else if (strcmp(argv[1],"--update")==0){
  545.             if (perm_rootaccess("set file permissions")){
  546.                 net_introlog ("fixperm --update");
  547.                 ret = fixperm_check (argc-2,argv+2);
  548.             }else{
  549.                 ret = -1;
  550.             }
  551.         }else{
  552.             usage();
  553.         }
  554.     }
  555.     return ret;
  556. }
  557.  
  558.